<?php
/**
 * 
 * +------------------------------------------------------------+
 * @category Form 
 * +------------------------------------------------------------+
 * 表单自动验证类，在Model中会调用该类
 * +------------------------------------------------------------+
 *
 * @author anzai <236049524@qq.com>
 * @copyright http://www.judianyun.com 2012
 * @version 1.0
 *
 * Modified at : 2012-02-17 11:30:11
 *
 */
class Form extends Base {
	///执行过程中所产生的错误
	private $_errors;
	
	///存储已验证的表单数据
	private $_vals = array();
	
	///Model实例
	private $_model = null;
	
	///存储表单所提交的数据
	private $_datas = null;
	
	//预定义验证格式正则
    static $regex = array(
            'require'=> '/.*/', //匹配任意字符，除了空和断行符
            'email' => '/^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/',
            'phone' => '/^(0?\d{2,3}-?)?\d{5,9}$/',
            'mobile' => '/^((\(\d{2,3}\))|(\d{3}\-))?(1[0-9])\d{9}$/',
            'url' => '/^http[s]?:\/\/[A-Za-z0-9]+\.[A-Za-z0-9]+[\/=\?%\-&_~`@[\]\':+!]*([^<>\"\"])*$/',
            'currency' => '/^\d+(\.\d+)?$/',
            'number' => '/\d+$/',
            'zip' => '/^[1-9]\d{5}$/',
            'qq' => '/^[1-9]\d{4,12}$/',
            'integer' => '/^[-\+]?\d+$/',
            'double' => '/^[-\+]?\d+(\.\d+)?$/',
    		'card' =>'/^(\d{14}|\d{17})(\d|[xX])$/',
            'english' => '/^[A-Za-z]+$/',
    		'string' => '/^[A-Za-z_]+[0-9_a-zA-Z]*$/',
    		'ip' => '/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/',
    		'image' => '/^.*\.(gif|jpg|jpeg|bmp|png)$/i',
    		'date' => '/^[1-9]\d{3}-\d{2}-\d{2}$/',
    		'sku'	=> '/^[0-9]{1}(\d{11,12}|\d{7})$/'
    );
    
    ///预定义需进行验证的表单数据
    private $_validata = array();
	
	function __construct(Model $model=null, $validata=array()){
		parent::__construct();
		if(file_exists(__INCLUDES_PATH__.'Conf/regex.php')){
			self::$regex = extend(self::$regex, require __INCLUDES_PATH__.'Conf/regex.php');
		}
		if ($this->_model===null)
			$this->_model = $model;
		$this->_validata = $validata;
		$this->_datas = xaddslashes($this->isPost() ? $_POST : $_GET);
	}
	
	/**
	 * 记录执行过程中的错误信息
	 * @param $key 键
	 * @param $value 值
	 */
	private function _addError($key, $value){
		$this->_errors[$key] = $value;
	}
	
	/**
	 * 
	 * +------------------------------------------------------------+
	 * @name check
	 * +------------------------------------------------------------+
	 * 检查数据格式正确性
	 * +------------------------------------------------------------+
	 *
	 * @author anzai <236049524@qq.com>
	 * @version 1.0
	 *
	 * @example
	 *
	 * @param string $name  若正则未定义则使用该参数作为正则表达式
	 * @param string $value
	 *
	 */
	static public function check($name, $value){
		if (empty($name)) return true;
		$regexs = self::$regex;
		$name = strtolower($name);
		if (array_key_exists($name,$regexs)) {
			return preg_match($regexs[$name], $value);
		}else
			return preg_match($name, $value);
	}
	
	/**
	 * 
	 * +------------------------------------------------------------+
	 * @name getError
	 * +------------------------------------------------------------+
	 * 获取执行过程中产生的错误信息
	 * +------------------------------------------------------------+
	 *
	 * @author anzai <236049524@qq.com>
	 * @version 1.0
	 *
	 * @example
	 *
	 * @param string $key 指定要获取的错误信息，未指定则返回所有错误信息
	 *
	 */
	public function getError($key=''){
		if (empty($key))
			return $this->_errors;
		else
			return $this->_errors[$key];
	}
	
	/**
	 * 
	 * +------------------------------------------------------------+
	 * @name hasError
	 * +------------------------------------------------------------+
	 * 判断执行过程中是否产生错误信息
	 * +------------------------------------------------------------+
	 *
	 * @author anzai <236049524@qq.com>
	 * @version 1.0
	 *
	 * @example
	 *
	 * @param string $key 指定是否产生某个错误信息，未指定则判断整个执行过程是否有产生错误
	 * @return 存在错误信息返回true
	 *
	 */
	public function hasError($key=''){
		if (empty($key))
			return !empty($this->_errors);
		else
			return isset($this->_errors[$key]);
	}

	/**
	 * 
	 * +------------------------------------------------------------+
	 * @name _isAction
	 * +------------------------------------------------------------+
	 * 根据用户定义的操作判断是否进行某验证等操作
	 * +------------------------------------------------------------+
	 *
	 * @author anzai <236049524@qq.com>
	 * @version 1.0
	 *
	 * @example
	 *
	 * @param string $action add：插入数据操作、edit更新数据操作，其他为两者都进行验证等操作
	 *
	 */
	private function _isAction($action){
		$action = strtolower($action);
		switch ($action){
			case 'add'://插入新数据
				return !$this->_model->isSaved();
				break;
			case 'edit'://更新数据
				return $this->_model->isSaved();
			default://两者都进行验证
				return true;
				break;
		}
	}
	
	///表单自动验证全过程
	private function _process(){
		if (empty($this->_validata)) return true;
		$compare = array('gt', 'lt', 'egt', 'elt');
		foreach ($this->_validata as $name => $validata){
			//判断提交表单是否进行数据验证
			if ($this->_isAction($validata['action'])){
				$validata['desc'] = empty($validata['desc']) ? Helper::L($validata['lang']) : $validata['desc'];
				$value = $this->_datas[$name];
				if (!$validata['empty']){//验证是否为空
					if($value == ''){
						$this->_addError($name, $validata['desc'] . Helper::L('CLS_FORM_EMPTY_ERROR'));
						continue;
					}
				}
				
				//数据正确性验证
				if($validata['verify']){
					$vfunc = $validata['verify'];
					if (!function_exists($vfunc)){
						E::halt($validata['desc'] . Helper::L('CLS_FORM_VERIFY_ERROR') .' <b>' . $vfunc . '</b>', 'sys', true);
					}elseif (!$vfunc($value)){
						$this->_addError($name, $validata['desc'] . Helper::L('CLS_FORM_INPUY_ERROR'));
						continue;
					}
				}
				
				//验证长度是否符合规定
				if($validata['min'] > 0 || $validata['max'] > 0){
					$len = strlen($value);
					if($validata['min'] > 0 && $len < $validata['min']){
						$this->_addError($name,sprintf(Helper::L('CLS_FORM_STRLEN_LT_ERROR'), $validata['desc'], $validata['min']));
						continue;
					}
					
					if($validata['max'] > 0 && $len > $validata['max']){
						$this->_addError($name, sprintf(Helper::L('CLS_FORM_STRLEN_GT_ERROR'), $validata['desc'], $validata['max']));
						continue;
					}
					unset($len);
				}
				
				foreach ($compare as $sign){
					if (isset($validata[$sign])){
						$signValue = is_string($validata[$sign]) && isset($this->_datas[$validata[$sign]]) ? $this->_datas[$validata[$sign]] : $validata[$sign];
						$continue = true;
						switch ($sign){
							case 'gt':
								$continue = $value > $signValue;
								break;
							case 'lt':
								$continue = $value < $signValue;
								break;
							case 'egt':
								$continue = $value >= $signValue;
								break;
							case 'elt':
								$continue = $value <= $signValue;
								break;
							default:
								$continue = true;
						}
						if (!$continue){
							$this->_addError($name, $validata['desc'] . Helper::L('CLS_FORM_' . strtoupper($sign) . $signValue));
						}
					}
				}
				
				//检查格式的正确性
				if($value!='' && !$this->check($validata['regex'], $value)){
					$this->_addError($name, $validata['desc'] . Helper::L('CLS_FORM_FORMAT_ERROR'));
					continue;
				}
				
				//检查值是否与某个表单域或值相等
				if(!empty($validata['eq'])){
					$_desc = empty($this->_validata[$validata['eq']]['desc']) ? $this->_validata[$validata['eq']]['lang']:$this->_validata[$validata['eq']]['desc'];
					if (isset($this->_validata[$validata['eq']])){
						if($value != $this->_datas[$validata['eq']])
							$this->_addError($name, $validata['desc'] . Helper::L('CLS_FORM_EQUAL_ERROR') . $_desc);
					}else{
						$eqValue = isset($this->_datas[$validata['eq']]) ? $this->_datas[$validata['eq']] : $validata['eq'];
						if($value != $eqValue)
							$this->_addError($name, sprintf(Helper::L('CLS_FORM_INPUT_ERROR'), $validata['desc']));
					}
					unset($eqValue);
				}
				
				//预处理数据
				if(!empty($validata['func'])){
					$func = $validata['func'];
					
					//若预处理函数不存在，则进行提示
					if(!function_exists($func))
						E::halt($validata['desc'] . Helper::L('CLS_FORM_FIRSTFUN_ERROR') . ' <b>' . $func . '</b>', 'sys', true);
					$value = $func($value);
				}
				
				//验证数据在数据库表中是否为唯一值
				if($value !='' && isset($validata['unique']) && $validata['unique']){
					if($this->_model->dataExists($name,$value)){
						$this->_addError($name, $validata['desc'] . Helper::L('CLS_FORM_VALUE_EXIST_ERROR'));
						continue;
					}
				}
				$this->_vals[$name] = $value;
				unset($value);
			}
		}
		
		return !$this->hasError();
	}
	
	//提交表单想数据库表插入或更新数据
	public function submit($transaction = true,$d=FALSE){
		if ($this->_process()){
			$fields = $this->_model->getFields();
			if (empty($fields))
				E::halt(sprintf(Helper::L('CLS_FORM_NOFIELD_ERROR'), $this->_model->getTable()), 'sys', true);
			
			//过滤不存在的字段信息
			foreach ($fields as $field){
				if(!isset($this->_datas[$field])) continue;
				$value = isset($this->_vals[$field]) ? $this->_vals[$field] : $this->_datas[$field];
				$this->_model->set($field, $value);
				unset($value);
			}
			
			if (!$this->_model->save($transaction)){
				$error = $this->_model->getError();
				if ($error){
					$this->_errors = extend($this->_errors, $error);
				}else{
					$this->_addError('sys', sprintf(Helper::L('CLS_FORM_SUBMIT_ERROR'), $this->_model->getTable()));
				}
			}
				
		}
		
		return !$this->hasError();
	}
}

?>